package com.okex.demo.task;

import com.alibaba.fastjson.JSONObject;
import com.okex.demo.model.Account;
import com.okex.demo.model.PositionInfo;
import com.okex.demo.model.TickerInfo;
import com.okex.demo.service.OkexApiService;
import com.okex.demo.service.WebSocketPushService;
import com.okex.open.api.bean.account.param.SetLeverage;
import com.okex.open.api.bean.trade.param.PlaceOrder;
import com.okex.open.api.service.account.AccountAPIService;
import com.okex.open.api.service.trade.TradeAPIService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.okex.demo.service.AccountService;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * OKX数据定时任务
 * 
 * 注意：持仓数据相关定时任务已禁用
 * 改为使用PositionPollingService按需执行
 * 行情数据相关定时任务也已禁用，改为使用DataPollingService按需执行
 */
@Slf4j
@Component
public class OkexDataTask {

    @Autowired
    private OkexApiService okexApiService;

    @Autowired
    private WebSocketPushService webSocketPushService;

    private TradeAPIService tradeAPIService;

    @Value("${okex.default.inst-id:BTC-USDT}")
    private String defaultInstId;
    @Autowired
    private AccountAPIService accountAPIService;

    @Autowired
    private AccountService accountService;

    /**
     * 定时获取持仓信息并推送
     * 已弃用，改为使用PositionPollingService按需执行
     */
    // @Scheduled(fixedDelay = 1000) - 已取消调度
    @Deprecated
    public void fetchPositionsAndPush() {
        log.info("开始获取持仓信息...");
        try {
            List<PositionInfo> positions = okexApiService.getPositions();
            log.info("获取到持仓信息: {} 条", positions.size());

            // 确保更新时间是最新的
            Date now = new Date();
            for (PositionInfo position : positions) {
                position.setUpdateTime(now);
                // 打印持仓信息，帮助调试
                log.info("持仓: {}, 方向: {}, 数量: {}",
                         position.getInstId(), position.getPosSide(), position.getPos());
            }

            // 即使没有持仓数据，也推送空列表
            webSocketPushService.pushPositions(positions);
            log.info("已推送持仓信息到前端");

            if (positions.isEmpty()) {
                return;
            }

            // 处理每个持仓信息
            for (PositionInfo position : positions) {
                try {
                    // 查找对应的账户配置
                    Optional<Account> accountOpt = accountService.findByInstId(position.getInstId());
                    if (!accountOpt.isPresent()) {
                        log.warn("未找到产品 {} 的账户配置，跳过交易逻辑", position.getInstId());
                        continue;
                    }

                    Account account = accountOpt.get();
                    // 添加最新成交价到持仓信息中，用于前端显示
                    TickerInfo ticker = okexApiService.getTicker(position.getInstId());
                    if (ticker != null) {
                        position.setLast(ticker.getLast());
                    }

                    if ("cross".equals(position.getMgnMode())) {
                        // 全仓模式
                        if ("long".equals(position.getPosSide())) {
                            // 全仓多仓
                            processLongCrossPosition(position, account);
                        } else if ("short".equals(position.getPosSide())) {
                            // 全仓空仓
                            processShortCrossPosition(position, account);
                        }
                    } else if ("isolated".equals(position.getMgnMode())) {
                        // 逐仓模式
                        if ("long".equals(position.getPosSide())) {
                            // 逐仓多仓
                            processLongIsolatedPosition(position, account);
                        } else if ("short".equals(position.getPosSide())) {
                            // 逐仓空仓
                            processShortIsolatedPosition(position, account);
                        }
                    }
                } catch (Exception e) {
                    log.error("处理持仓 {} 交易逻辑时发生错误: {}", position.getInstId(), e.getMessage(), e);
                }
            }

            // 更新后的持仓信息再次推送到前端
            webSocketPushService.pushPositions(positions);
        } catch (Exception e) {
            log.error("获取并推送持仓信息任务异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 定时获取行情信息并推送
     * 已弃用，改为使用DataPollingService按需执行
     */
    // @Scheduled(fixedDelay = 1000) - 已取消调度
    @Deprecated
    public void fetchTickerAndPush() {
        log.info("开始获取行情信息: {}", defaultInstId);
        try {
            TickerInfo ticker = okexApiService.getTicker(defaultInstId);
            if (ticker != null) {
                // 确保更新时间是最新的
                ticker.setUpdateTime(new Date());

            webSocketPushService.pushTicker(ticker);
                log.info("已推送行情信息: {}", defaultInstId);
            } else {
                log.warn("无法获取产品 {} 的行情数据，跳过推送", defaultInstId);
            }
        } catch (Exception e) {
            log.error("获取并推送行情信息任务异常: {}", e.getMessage(), e);
        }
    }

    /*全仓多仓止盈*/
    private void processLongCrossPosition(PositionInfo info, Account account) {
        //如果全仓多仓成本等于0，开仓
        if(account.getCrossLongCost().compareTo(BigDecimal.ZERO) == 0){
            //将开仓价格传递到多仓成本
            account.setCrossLongCost(info.getAvgPx());
            // 保存account更新
            saveAccount(account);
            return;
        }
        //判断全仓多仓止盈
        //计算基准点位
        BigDecimal basePrice = account.getCrossLongCost().add(account.getCrossPriceDiff().multiply(new BigDecimal(account.getCrossLongReplenishCount())));
        //计算止盈点位
        BigDecimal takeProfitPrice = basePrice.add(account.getCrossTakeProfit());
        //检查是否达到止盈条件
        if(info.getLast().compareTo(takeProfitPrice) >= 0){
            //平多仓
            placeOrder(info.getInstId(), info.getMgnMode(), "sell", "long", info.getAvailPos().toPlainString());
            //将全仓多仓成本和次数重置
            account.setCrossLongReplenishCount(1);
            account.setCrossLongCost(BigDecimal.ZERO);
            // 保存account更新
            saveAccount(account);
        }
    }

    /*全仓空仓止盈*/
    private void processShortCrossPosition(PositionInfo info, Account account) {
        //如果全仓空仓成本等于0，开仓
        if(account.getCrossShortCost().compareTo(BigDecimal.ZERO) == 0){
            //将开仓价格传递到空仓成本
            account.setCrossShortCost(info.getAvgPx());
            // 保存account更新
            saveAccount(account);
            return;
        }
        //判断全仓空仓止盈
        //计算基准点位
        BigDecimal basePrice = account.getCrossShortCost().subtract(account.getCrossPriceDiff().multiply(new BigDecimal(account.getCrossShortReplenishCount())));
        //计算止盈点位
        BigDecimal takeProfitPrice = basePrice.subtract(account.getCrossTakeProfit());
        //检查是否达到止盈条件
        if(info.getLast().compareTo(takeProfitPrice) <= 0){
            //平空仓
            placeOrder(info.getInstId(), info.getMgnMode(), "buy", "short", info.getAvailPos().toPlainString());
            //将全仓空仓成本和次数重置
            account.setCrossShortReplenishCount(1);
            account.setCrossShortCost(BigDecimal.ZERO);
            // 保存account更新
            saveAccount(account);
        }
    }

    /*全仓多仓补仓*/
    private void processLongCrossReplenish(PositionInfo info, Account account) {
        //获取多仓补仓次数
        int f = account.getCrossLongReplenishCount();
        //获取全仓多仓成本
        BigDecimal h;
        if(account.getCrossLongCost().compareTo(BigDecimal.ZERO) == 0){
            h = info.getAvgPx();
            account.setCrossLongCost(h);
            // 保存account更新
            saveAccount(account);
        } else {
            h = account.getCrossLongCost();
        }
        //判断补仓
        BigDecimal lastPrice = info.getLast();
        BigDecimal priceDiff = account.getCrossPriceDiff().multiply(new BigDecimal(f));
        BigDecimal targetPrice = h.subtract(priceDiff);

        if(lastPrice.compareTo(targetPrice) <= 0){
            // 设置杠杆倍数
            setLeverage(info.getInstId(), account.getLeverage(), info.getMgnMode(), info.getPosSide());
            
            //全仓保证金张数,此处使用全仓价差保证金E
            String sz = calculateOrderSize(info, account.getLeverage(), account.getCrossPriceDiffMargin().doubleValue(), account.getFaceValue().doubleValue());
            //开多
            placeOrder(info.getInstId(), info.getMgnMode(), "buy", "long", sz);
            //多仓补仓次数加1
            account.setCrossLongReplenishCount(f + 1);
            // 保存account更新
            saveAccount(account);
        }
        //判断减仓
        if(f >= 2){
            BigDecimal reduceTargetPrice = h.subtract(account.getCrossPriceDiff().multiply(new BigDecimal(f - 2)));
            if(lastPrice.compareTo(reduceTargetPrice) >= 0){
                //全仓保证金张数,此处使用全仓价差保证金E
                String sz = calculateOrderSize(info, account.getLeverage(), account.getCrossPriceDiffMargin().doubleValue(), account.getFaceValue().doubleValue());
                //平多
                placeOrder(info.getInstId(), info.getMgnMode(), "sell", "long", sz);
                //多仓补仓次数减1
                account.setCrossLongReplenishCount(f - 1);
                // 保存account更新
                saveAccount(account);
            }
        }
    }

    /*全仓转逐仓多仓*/
    private void processCrossToIsolatedLong(PositionInfo info, Account account) {
        //判断是否进行全仓转逐仓
        if(account.getIsTransferIsolatedLong()){
            //计算1:1撮合价格
            BigDecimal takeProfitPrice = account.getCrossToIsolatedLongCost().add(account.getConversionPriceDiff());

            if(info.getLast().compareTo(takeProfitPrice) >= 0){
                // 设置杠杆倍数
                setLeverage(info.getInstId(), account.getLeverage(), "isolated", "long");
                
                //计算全仓保证金，使用全仓保证金D
                String sz = calculateOrderSize(info, account.getLeverage(), account.getCrossMargin().doubleValue(), account.getFaceValue().doubleValue());
                //开逐仓多仓
                placeOrder(info.getInstId(), "isolated", "buy", "long", sz);
                //设置是否继续追加逐仓多仓
                account.setIsTransferIsolatedLong(false);
                // 保存account更新
                saveAccount(account);
        }
    }
    }

    /*全仓转逐仓空仓*/
    private void processCrossToIsolatedShort(PositionInfo info, Account account) {
        //判断是否进行全仓转逐仓
        if(account.getIsTransferIsolatedShort()){
            //计算1:1撮合价格
            BigDecimal takeProfitPrice = account.getCrossToIsolatedShortPriceDiff().subtract(account.getConversionPriceDiff());

            if(info.getLast().compareTo(takeProfitPrice) <= 0){
                // 设置杠杆倍数
                setLeverage(info.getInstId(), account.getLeverage(), "isolated", "short");
                
                //计算全仓保证金，使用全仓保证金D
                String sz = calculateOrderSize(info, account.getLeverage(), account.getCrossMargin().doubleValue(), account.getFaceValue().doubleValue());
                //开逐仓空仓
                placeOrder(info.getInstId(), "isolated", "sell", "short", sz);
                //不再转移逐仓空仓
                account.setIsTransferIsolatedShort(false);
                // 保存account更新
                saveAccount(account);
            }
        }
    }

    /*逐仓多仓补仓*/
    private void processLongIsolatedPosition(PositionInfo info, Account account) {
        //逐仓多仓补仓次数
        int q = account.getIsolatedLongReplenishCount();
        //逐仓多仓成本
        BigDecimal v;
        if(account.getIsolatedLongCost().compareTo(BigDecimal.ZERO) == 0){
            v = info.getAvgPx();
            account.setIsolatedLongCost(v);
            // 保存account更新
            saveAccount(account);
        } else {
            v = account.getIsolatedLongCost();
        }
        //逐仓多仓加仓
        BigDecimal lastPrice = info.getLast();
        BigDecimal priceDiff = account.getIsolatedPriceDiff().multiply(new BigDecimal(q));
        BigDecimal targetPrice = v.add(priceDiff);

        if(lastPrice.compareTo(targetPrice) >= 0){
            // 设置杠杆倍数
            setLeverage(info.getInstId(), account.getLeverage(), info.getMgnMode(), info.getPosSide());
            
            String sz = calculateOrderSize(info, account.getLeverage(), account.getIsolatedPriceDiffMargin().doubleValue(), account.getFaceValue().doubleValue());
            placeOrder(info.getInstId(), info.getMgnMode(), "buy", "long", sz);
            account.setIsolatedLongReplenishCount(q+1);
            // 保存account更新
            saveAccount(account);
        }
        //逐仓多仓平空
        BigDecimal halfN = account.getIsolatedPriceDiff().divide(new BigDecimal(2));
        BigDecimal closeTargetPrice = v.add(account.getIsolatedPriceDiff().multiply(new BigDecimal(q-1))).subtract(halfN);

        if(lastPrice.compareTo(closeTargetPrice) <= 0){
            placeOrder(info.getInstId(), info.getMgnMode(), "sell", "long", info.getAvailPos().toPlainString());
            //将平仓价上传到全仓转逐仓多仓成本
            account.setCrossToIsolatedLongCost(v.add(account.getIsolatedPriceDiff().multiply(new BigDecimal(q-1))));
            //逐仓补仓次数恢复到默认状态1
            account.setIsolatedLongReplenishCount(1);
            //逐仓多仓成本恢复到默认状态0
            account.setIsolatedLongCost(BigDecimal.ZERO);
            //是否转移逐仓多仓恢复到默认状态
            account.setIsTransferIsolatedLong(true);
            // 保存account更新
            saveAccount(account);
        }
    }

    /*逐仓空仓补仓*/
    private void processShortIsolatedPosition(PositionInfo info, Account account) {
        //逐仓空仓补仓次数
        int r = account.getIsolatedShortReplenishCount();
        //逐仓空仓成本
        BigDecimal w;
        if(account.getIsolatedShortCost().compareTo(BigDecimal.ZERO) == 0){
            w = info.getAvgPx();
            account.setIsolatedShortCost(w);
            // 保存account更新
            saveAccount(account);
        } else {
            w = account.getIsolatedShortCost();
        }
        //逐仓空仓补仓
        BigDecimal lastPrice = info.getLast();
        BigDecimal priceDiff = account.getIsolatedPriceDiff().multiply(new BigDecimal(r));
        BigDecimal targetPrice = w.subtract(priceDiff);

        if(lastPrice.compareTo(targetPrice) <= 0){
            // 设置杠杆倍数
            setLeverage(info.getInstId(), account.getLeverage(), info.getMgnMode(), info.getPosSide());

            String sz = calculateOrderSize(info, account.getLeverage(), account.getIsolatedPriceDiffMargin().doubleValue(), account.getFaceValue().doubleValue());
            placeOrder(info.getInstId(), info.getMgnMode(), "sell", "short", sz);
            account.setIsolatedShortReplenishCount(r+1);
            // 保存account更新
            saveAccount(account);
        }
        //逐仓空仓平空
        BigDecimal halfN = account.getIsolatedPriceDiff().divide(new BigDecimal(2));
        BigDecimal closeTargetPrice = w.subtract(account.getIsolatedPriceDiff().multiply(new BigDecimal(r-1))).add(halfN);

        if(lastPrice.compareTo(closeTargetPrice) >= 0){
            placeOrder(info.getInstId(), info.getMgnMode(), "buy", "short", info.getAvailPos().toPlainString());
            //将平仓价上传到全仓转逐仓空仓成本
            account.setCrossToIsolatedShortPriceDiff(w.subtract(account.getIsolatedPriceDiff().multiply(new BigDecimal(r-1))));
            //逐仓补仓次数恢复到默认状态1
            account.setIsolatedShortReplenishCount(1);
            //逐仓空仓成本恢复到默认状态0
            account.setIsolatedShortCost(BigDecimal.ZERO);
            //是否转移逐仓空仓恢复到默认状态
            account.setIsTransferIsolatedShort(true);
            // 保存account更新
            saveAccount(account);
        }
    }

    /*根据产品ID获取account*/
    private Optional<Account> getAccountByInstId(String instId) {
        return accountService.findByInstId(instId);
    }

    /*下单*/
    private void placeOrder(String instId, String mgnMode, String side, String posSide, String sz) {
        try {
            // 使用OkexApiService进行下单，该服务已经封装了API调用
            JSONObject result = okexApiService.placeOrder(instId, mgnMode, side, posSide, sz);
            
            if (result != null && result.getInteger("code") == 0) {
                log.info("下单成功: instId={}, mgnMode={}, side={}, posSide={}, sz={}",
                        instId, mgnMode, side, posSide, sz);
            } else {
                String errorCode = result != null ? String.valueOf(result.get("code")) : "unknown";
                String errorMsg = result != null ? String.valueOf(result.get("msg")) : "unknown";
                log.error("下单失败: instId={}, mgnMode={}, side={}, posSide={}, sz={}, code={}, msg={}",
                        instId, mgnMode, side, posSide, sz, errorCode, errorMsg);
            }
        } catch (Exception e) {
            log.error("下单异常: instId={}, mgnMode={}, side={}, posSide={}, sz={}, error={}",
                    instId, mgnMode, side, posSide, sz, e.getMessage(), e);
        }
    }

    /*设置杠杆*/
    private void setLeverage(String instId, String lever, String mgnMode, String posSide) {
        try {
            // 使用OkexApiService中的placeOrder方法，它内部会处理杠杆设置
            // 创建一个最小下单量的订单来触发杠杆设置
            JSONObject result = okexApiService.placeOrder(instId, mgnMode, 
                    "long".equals(posSide) ? "buy" : "sell", 
                    posSide, "1", lever);
            
            if (result != null && result.getInteger("code") == 0) {
                log.info("设置杠杆成功: instId={}, lever={}, mgnMode={}, posSide={}",
                        instId, lever, mgnMode, posSide);
            } else {
                String errorCode = result != null ? String.valueOf(result.get("code")) : "unknown";
                String errorMsg = result != null ? String.valueOf(result.get("msg")) : "unknown";
                log.error("设置杠杆失败: instId={}, lever={}, mgnMode={}, posSide={}, code={}, msg={}",
                        instId, lever, mgnMode, posSide, errorCode, errorMsg);
            }
        } catch (Exception e) {
            log.error("设置杠杆异常: instId={}, lever={}, mgnMode={}, posSide={}, error={}",
                    instId, lever, mgnMode, posSide, e.getMessage(), e);
        }
    }

    /*计算订单数量*/
    private String calculateOrderSize(PositionInfo info, String lever, double margin, double faceValue) {
        try {
            BigDecimal price = info.getLast();
            if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("计算订单数量失败: 价格为空或小于等于0");
                return "1"; // 默认值
            }

            // 计算合约面值（单位：USD）
            BigDecimal contractValue = price.multiply(new BigDecimal(faceValue));
            
            // 确保面值不为0，避免除以0的错误
            if (contractValue.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("计算订单数量失败: 合约面值为0或负数");
                return "1"; // 默认值
            }

            // 计算可买入的合约数量
            BigDecimal marginAmount = new BigDecimal(margin);
            BigDecimal leverNum = new BigDecimal(lever);
            
            // 张数 = 保证金*杠杆倍数 / (面值*价格)
            BigDecimal size = marginAmount.multiply(leverNum).divide(contractValue, 8, BigDecimal.ROUND_DOWN);
            
            // 确保至少有1张
            if (size.compareTo(BigDecimal.ONE) < 0) {
                size = BigDecimal.ONE;
            } else {
                // 取整，不要小数部分
                size = new BigDecimal(size.intValue());
            }

            // 转换为字符串，不使用科学计数法
            return size.stripTrailingZeros().toPlainString();
        } catch (Exception e) {
            log.error("计算订单数量异常", e);
            return "1"; // 默认值
        }
        }

    /*保存账户更新*/
    private void saveAccount(Account account) {
        try {
            accountService.save(account);
        } catch (Exception e) {
            log.error("保存账户更新失败: {}", account.getInstId(), e);
        }
    }
}
